﻿/// -----------------------------------------------------------------
/// BookmarkManipulator.cs: provides methods for extracting, 
/// updating and deleting Clips and Segments in the Database.
/// License: see http://mve.codeplex.com/license; All Rights follows the MS-PL
/// Current owner: shiniwa
/// The project decription: please refer to http://codeplex.com/mve/
/// -----------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Xml;
using System.Data;
using System.Data.SqlClient;

namespace MVEContentSvc.ClipOperations
{
    /*
     * 日本SGI株式会社
     * ヨハンソン・ヘンリク
     * johansson@sgi.co.jp
     * 
     * Change Log:
     * ---------------------------------------------------------------------------
     * 2009.01.06	Johansson Henrik		Class Created.
     * 2009.01.07							Updated GetClip to use the various Loader classes.
     *										Those Updates have not been Tested yet.
     * 2009.01.09							Updated GetCLip to always return an XML string.
     *										Currently the application expect the reply to be an Error
     *										Xml Document (status = 1) even if an exception is thrown
     *										or no matching data was founds.
     */

    /// <summary>
    /// This static class provides methods for extracting, 
    /// updating and deleting Clips and Segments in the Database.
    /// Use the static methods in this class to perform Clip and 
    /// Segment related operations on the Database.
    /// </summary>
    /// <remarks>INSERT:Creds</remarks>
    internal static class ClipManipulator
    {
        /// <summary>
        /// Gets all the Clips registered for the given User Id.
        /// </summary>
        /// <remarks>Not Implemented. Was never called in original Service.</remarks>
        internal static string QueryClipsForUser(int userId, SqlConnection connection)
        {
            throw new NotImplementedException(
                Resources.NotImplementedInOriginal);

        }//end:QueryClipsForUser

        /// <summary>
        /// Get all the Segments that make up a given clip, given a clip Id.
        /// </summary>
        /// <remarks>Not Implemented. Was never called in original Service.</remarks>
        internal static string GetClipSegments(int clipId, SqlConnection connection)
        {
            throw new NotImplementedException(
                Resources.NotImplementedInOriginal);
        }//end:GetClipSegments

        /// <summary>
        /// Get a single clip out of the DB
        /// Original Name = Clip
        /// </summary>
        /// <remarks>Done</remarks>
        /// <param name="clipId">Id of the Clip to pull from the DB</param>
        /// <param name="connection">Sql Connection</param>
        /// <returns>The Xml string that contains the response document.</returns>
        internal static string GetClip(int clipId, SqlConnection connection)
        {

            string result = string.Empty;
            try
            {
                Dictionary<Segment, List<KeywordOperations.Keyword>> segmentKeywords =
                    new Dictionary<Segment, List<KeywordOperations.Keyword>>();

                Clip parentClip = ClipLoader.LoadClipFromDatabase(clipId, connection);
                if (parentClip == null)
                    throw new ArgumentNullException("The parentClip is null (not found?)");

                List<Segment> segments =
                    SegmentLoader.LoadSegmentsForClipFromDatabase(parentClip.Id, connection);

                //There might be Clips with no segments?
                if (segments != null)
                {
                    foreach (Segment seg in segments)
                    {
                        List<KeywordOperations.Keyword> segKeywords =
                            KeywordOperations.KeywordLoader.LoadKeywordsForSegmentFromDatabase(
                                    seg.Id, connection);

                        //There might be Segments with no keywords?
                        if (segKeywords != null)
                            segmentKeywords.Add(seg, segKeywords);
                        else
                            segmentKeywords.Add(seg, new List<KeywordOperations.Keyword>());
                    }

                }

                //If we made it here we have all the data needed to build a complete clip response
                //Next, build the Xml Document.
                XmlDocument doc = null;
                XmlElement dataRoot = XmlConstructor.FormatResponseDocument(ref doc);

                XmlElement clipRoot = XmlConstructor.AddClipNodeToDocument(doc, parentClip, dataRoot);
                foreach (KeyValuePair<Segment, List<KeywordOperations.Keyword>>
                    kvSegKey in segmentKeywords)
                {

                    XmlElement segmentRoot = XmlConstructor.AddSegmentNodeToClip(
                        doc, kvSegKey.Key, parentClip.OnAirDate, clipRoot);

                    if (kvSegKey.Value.Count != 0)
                    {
                        XmlElement kwRoot = doc.CreateElement("keywords");
                        segmentRoot.AppendChild(kwRoot);

                        foreach (KeywordOperations.Keyword keyword in kvSegKey.Value)
                        {
                            XmlConstructor.AddKeywordNodeToSegment(
                                doc, keyword, kwRoot);
                        }
                    }
                }

                result = doc.OuterXml;

            }
            catch (Exception ex)
            {
                ErrorHandler.LogMessage(ex.Message, false);
                result =
                    XmlConstructor.GetOperationFailedResponseDocument().OuterXml;
            }

            return result;
        }//end:GetClip

        /// <summary>
        /// Gets the parent Clip of a segment, given a segment Id. This method
        /// first gets the Segment out of the segment table, pulls out its clip_id
        /// value and then calls GetClip with the clip_id value.
        /// Original Name = ClipBySegmentId
        /// </summary>
        /// <remarks>Done</remarks>
        /// <param name="segmentId">Id of the segment whose parent clip to retreive</param>
        /// <param name="connection">Sql Connection</param>
        /// <returns>The Xml string that contains the response document.</returns>
        internal static string GetClipBySegmentId(int segmentId, SqlConnection connection)
        {
            SqlCommand command = new SqlCommand();
            SqlDataReader reader = null;
            command.CommandTimeout = 60;

            int? parentClipId = null;

            string result = string.Empty;
            try
            {
                command.Connection = connection;
                command.CommandType = System.Data.CommandType.StoredProcedure;
                command.CommandText = "GetSegmentById";

                command.Parameters.Add("segmentId", SqlDbType.Int).Value = segmentId;
                reader = command.ExecuteReader();

                if (reader.HasRows)
                {
                    reader.Read();
                    parentClipId = reader.GetInt32(1);
                }


                command.Dispose();
                reader.Close();
                reader.Dispose();

                string clipResult = string.Empty;
                if (parentClipId.HasValue)
                {
                    clipResult = ClipManipulator.GetClip(parentClipId.Value, connection);
                    if (string.IsNullOrEmpty(clipResult) == false)
                        result = clipResult;
                }

            }
            catch (NullReferenceException ex)
            {
                ErrorHandler.LogMessage(ex.Message, false);
                result = string.Empty;
            }
            catch (SqlException ex)
            {
                ErrorHandler.LogMessage(ex.Message, false);
                result = string.Empty;
            }
            catch (InvalidOperationException ex)
            {
                ErrorHandler.LogMessage(ex.Message, false);
                result = string.Empty;
            }
            catch (IndexOutOfRangeException ex)
            {
                ErrorHandler.LogMessage(ex.Message, false);
                result = string.Empty;
            }
            finally
            {
                command.Dispose();
                if (reader != null)
                {
                    reader.Close();
                    reader.Dispose();
                }
            }

            return result;
        }//end:GetClipBySegmentId
    }
}
